package com.chensi.admin.shop.service.impl;

import com.chensi.admin.shop.common.BaseErrorCode;
import com.chensi.admin.shop.common.Constants;
import com.chensi.admin.shop.domain.Goods;
import com.chensi.admin.shop.domain.GoodsType;
import com.chensi.admin.shop.dto.GoodsDTO;
import com.chensi.admin.shop.service.GoodsService;
import com.chensi.admin.shop.service.GoodsTypeService;
import com.chensi.admin.shop.util.BeanUtils;
import com.chensi.admin.shop.util.CommonUtil;
import com.chensi.admin.shop.util.SpecificationUtil;
import com.chensi.admin.shop.dao.GoodsTypeRepository;
import com.chensi.admin.shop.exception.BaseException;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * @author si.chen
 * @date 2019/7/12 8:57
 */
@Service
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class GoodsTypeServiceImpl implements GoodsTypeService {

    private final GoodsTypeRepository goodsTypeRepository;

    private final GoodsService goodsService;

    @Autowired
    public GoodsTypeServiceImpl(GoodsTypeRepository goodsTypeRepository, GoodsService goodsService) {
        this.goodsTypeRepository = goodsTypeRepository;
        this.goodsService = goodsService;
    }

    private GoodsType get(String id) throws BaseException {
        Optional<GoodsType> optional = goodsTypeRepository.findById(id);
        return optional.orElseThrow(() -> new BaseException(BaseErrorCode.ITEM_NOT_FOUND));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void create(GoodsType goodsType) throws BaseException {
        this.checkUniqueForCreate(goodsType);
        goodsTypeRepository.save(goodsType);

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(GoodsType goodsType) throws BaseException {
        GoodsType entity = this.get(goodsType.getId());
        BeanUtils.copyNotNullProperties(goodsType, entity);
        this.checkUniqueForUpdate(entity);
        goodsTypeRepository.save(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(String id) throws BaseException {
        //判断是否存在关联对象
        Goods param = new Goods();
        GoodsType type = new GoodsType();
        type.setId(id);
        param.setGoodsType(type);
        List<GoodsDTO> list = goodsService.list(param);
        if (CommonUtil.isNotEmptyList(list)) {
            throw new BaseException(BaseErrorCode.NOT_DELETE_IN_USE);
        } else {
            GoodsType entity = this.get(id);
            entity.setDeleted(Constants.YES);
            goodsTypeRepository.save(entity);
        }
    }

    @Override
    public List<GoodsType> list(GoodsType entity) {
        Sort sort = new Sort(Sort.Direction.ASC, "sort");
        return goodsTypeRepository.findAll(this.getSpecification(entity), sort);
    }

    @SuppressWarnings("Duplicates")
    private void checkUniqueForCreate(GoodsType entity) throws BaseException {
        if (StringUtils.isNotBlank(entity.getName())) {
            GoodsType param = new GoodsType();
            param.setName(entity.getName().trim());
            if (CommonUtil.isNotEmptyList(this.list(param))) {
                throw new BaseException(BaseErrorCode.NAME_IS_USED);
            }
        }
    }

    private void checkUniqueForUpdate(GoodsType entity) throws BaseException {
        if (StringUtils.isNotBlank(entity.getName())) {
            GoodsType param = new GoodsType();
            param.setName(entity.getName().trim());
            param.setIdNe(entity.getId());
            if (CommonUtil.isNotEmptyList(this.list(param))) {
                throw new BaseException(BaseErrorCode.NAME_IS_USED);
            }
        }
    }

    @SuppressWarnings("Duplicates")
    private Specification<GoodsType> getSpecification(GoodsType entity) {
        return (root, query, cb) -> {
            List<Predicate> list = new ArrayList<>();
            SpecificationUtil.baseSpecification(root, cb, list, entity);
            if (StringUtils.isNotBlank(entity.getName())) {
                Predicate predicate = cb.equal(root.get("name"), entity.getName().trim());
                list.add(predicate);
            }
            if (StringUtils.isNotBlank(entity.getParentId())) {
                Predicate predicate = cb.equal(root.get("parentId"), entity.getParentId().trim());
                list.add(predicate);
            }
            if (entity.getLevel() != null) {
                Predicate predicate = cb.equal(root.get("level"), entity.getLevel());
                list.add(predicate);
            }
            query.where(list.toArray(new Predicate[0]));
            return query.getRestriction();
        };
    }
}
